{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "7c1d11e8",
   "metadata": {},
   "outputs": [],
   "source": [
    "from google.colab import drive\n",
    "drive.mount('/content/drive')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "4eb3bd9a",
   "metadata": {},
   "outputs": [],
   "source": [
    "\"\"\"###Import Libraries\"\"\"\n",
    "from tensorflow.keras.layers import (Conv2D, Add,Activation,\n",
    "                                     Dropout,Dense,Flatten,Input,BatchNormalization,\n",
    "                                      ReLU,MaxPooling2D,Concatenate,GlobalAveragePooling2D\n",
    "                                     )\n",
    "from tensorflow.keras.models import Sequential\n",
    "from tensorflow.keras import optimizers, losses, metrics, regularizers, callbacks\n",
    "from tensorflow.keras.models import Model\n",
    "import tensorflow as tf\n",
    "import numpy as np\n",
    "import os"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "cff82f98",
   "metadata": {},
   "outputs": [],
   "source": [
    "\"\"\"#### Import Data\"\"\"\n",
    "\n",
    "path = 'data path'\n",
    "\n",
    "calssificatin_type = {\"binary\":1,\"superclasses\":5,\"subclasses\":23}\n",
    "classification_name=\"subclasses\"\n",
    "no_of_classes=calssificatin_type[classification_name]\n",
    "\n",
    "lead_type={\"lead-I\":1, \"bipolar-limb\":3 , \"unipolar-limb\":3, \"limb-leads\":6 , \"precordial-leads\":6,\"all-lead\":12}\n",
    "lead_name= \"all-lead\"\n",
    "no_of_leads=lead_type[lead_name]\n",
    "\n",
    "x_train = np.load(path + 'x_train.npy',allow_pickle=True)\n",
    "x_test  = np.load(path + 'x_test.npy',allow_pickle=True)\n",
    "y_train = np.load(path + 'y_train.npy',allow_pickle=True)\n",
    "y_test  = np.load(path + 'y_test.npy',allow_pickle=True)\n",
    "\n",
    "# print(x_train.shape)\n",
    "# print(x_test.shape)\n",
    "\n",
    "x_train = x_train.transpose(0, 2, 1)            # transpose working correctly\n",
    "x_test  = x_test.transpose(0, 2, 1)\n",
    "\n",
    "# print(x_train.shape)\n",
    "# print(x_test.shape)\n",
    "\n",
    "x_train = x_train.reshape(19601, no_of_leads, 1000, 1)   # Add another channel\n",
    "x_test  = x_test.reshape(2198, no_of_leads, 1000, 1)\n",
    "\n",
    "\n",
    "print(\"x_train :\", x_train.shape)\n",
    "print(\"y_train :\", y_train.shape)\n",
    "print(\"x_test  :\", x_test.shape)\n",
    "print(\"y_test  :\", y_test.shape)\n",
    "print('Data loaded')\n",
    "\n",
    "\n",
    "from sklearn.preprocessing import MultiLabelBinarizer\n",
    "\n",
    "if classification_name!=\"binary\":\n",
    "    mlb = MultiLabelBinarizer()\n",
    "    mlb.fit(y_train)\n",
    "    y_train = mlb.transform(y_train)\n",
    "\n",
    "    mlb = MultiLabelBinarizer()\n",
    "    mlb.fit(y_test)\n",
    "    y_test = mlb.transform(y_test)\n",
    "    print('Data proocessed')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "1e01b034",
   "metadata": {},
   "outputs": [],
   "source": [
    "\"\"\"#### Model\"\"\"\n",
    "\n",
    "input= Input(shape=(no_of_leads, 1000, 1))\n",
    "\n",
    "\n",
    "conv1 = Conv2D(filters=32, kernel_size=(1,7),strides=(1, 1))(input)\n",
    "batch1 = BatchNormalization()(conv1)\n",
    "relu1 = ReLU()(batch1)\n",
    "\n",
    "conv2 = Conv2D(filters=64, kernel_size=(1,5),strides=(1, 1))(relu1)\n",
    "batch2 = BatchNormalization()(conv2)\n",
    "relu2 = ReLU()(batch2)\n",
    "drop2 = Dropout(rate=0.1)(relu2)\n",
    "conv2 = Conv2D(filters=64, kernel_size=(1,5),strides=(1, 2))(drop2)\n",
    "\n",
    "max1 = MaxPooling2D(pool_size=(1,9),strides=(1,2))(relu1)\n",
    "conv_ = Conv2D(64, (1, 1))(max1)\n",
    "conc1 = Add()([conv2, conv_])\n",
    "\n",
    "batch3 = BatchNormalization()(conc1)\n",
    "relu3 = ReLU()(batch3)\n",
    "drop3 = Dropout(rate=0.1)(relu3)\n",
    "conv3 = Conv2D(filters=64, kernel_size=(1,5),strides=(1, 1))(drop3)\n",
    "batch3 = BatchNormalization()(conv3)\n",
    "relu3 = ReLU()(batch3)\n",
    "drop3 = Dropout(rate=0.1)(relu3)\n",
    "conv3 = Conv2D(filters=64, kernel_size=(1,5),strides=(1, 2))(drop3)\n",
    "\n",
    "\n",
    "max2 = MaxPooling2D(pool_size=(1,9),strides=(1,2))(conc1)\n",
    "conc2 = Add()([conv3, max2])\n",
    "\n",
    "batch3 = BatchNormalization()(conc2)\n",
    "relu3 = ReLU()(batch3)\n",
    "drop3 = Dropout(rate=0.1)(relu3)\n",
    "conv3 = Conv2D(filters=128, kernel_size=(1,5),strides=(1, 1))(drop3)\n",
    "batch3 = BatchNormalization()(conv3)\n",
    "relu3 = ReLU()(batch3)\n",
    "drop3 = Dropout(rate=0.1)(relu3)\n",
    "conv3 = Conv2D(filters=128, kernel_size=(1,5),strides=(1, 2))(drop3)\n",
    "\n",
    "\n",
    "max3 = MaxPooling2D(pool_size=(1,9),strides=(1,2))(conc2)\n",
    "conv_ = Conv2D(128, (1, 1))(max3)\n",
    "conc3 = Add()([conv3, conv_])\n",
    "\n",
    "batch3 = BatchNormalization()(conc3)\n",
    "relu3 = ReLU()(batch3)\n",
    "drop3 = Dropout(rate=0.1)(relu3)\n",
    "conv3 = Conv2D(filters=128, kernel_size=(1,5),strides=(1, 1))(drop3)\n",
    "batch3 = BatchNormalization()(conv3)\n",
    "relu3 = ReLU()(batch3)\n",
    "drop3 = Dropout(rate=0.1)(relu3)\n",
    "conv3 = Conv2D(filters=128, kernel_size=(1,5),strides=(1, 2))(drop3)\n",
    "\n",
    "\n",
    "max4 = MaxPooling2D(pool_size=(1,9),strides=(1,2))(conc3)\n",
    "conc4 = Add()([conv3, max4])\n",
    "          \n",
    "\n",
    "conv3 = Conv2D(filters=128, kernel_size=(no_of_leads, 1))(conc4)\n",
    "X = BatchNormalization()(conv3)\n",
    "X = ReLU()(X)\n",
    "X = GlobalAveragePooling2D()(X)\n",
    "\n",
    "X = Flatten()(X)\n",
    "print(X.shape)\n",
    "\n",
    "X = Dense(units=128, kernel_regularizer=tf.keras.regularizers.L2(0.005))(X)\n",
    "X = BatchNormalization()(X)\n",
    "X = ReLU()(X)\n",
    "X = Dropout(rate=0.1)(X)\n",
    "\n",
    "X = Dense(units=64, kernel_regularizer=tf.keras.regularizers.L2(0.009))(X)\n",
    "X = BatchNormalization()(X)\n",
    "X = ReLU()(X)\n",
    "X = Dropout(rate=0.15)(X)\n",
    "print('Added 2 fully connected layers')\n",
    "\n",
    "output = Dense(no_of_classes, activation='sigmoid')(X)\n",
    "model = Model(inputs=input, outputs=output)\n",
    "\n",
    "print(model.summary())\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "bc725d65",
   "metadata": {},
   "outputs": [],
   "source": [
    "\"\"\"#### Train Model\"\"\"\n",
    "import tensorflow as tf \n",
    "early    = callbacks.EarlyStopping(monitor=\"val_loss\", patience=6, restore_best_weights=True)\n",
    "reducelr = callbacks.ReduceLROnPlateau(monitor=\"val_loss\", patience=3)\n",
    "\n",
    "callback = [early, reducelr]\n",
    "\n",
    "\n",
    "model.compile(optimizer = optimizers.Adam(learning_rate=0.0005),\n",
    "              loss = losses.BinaryCrossentropy(),\n",
    "              metrics = [metrics.BinaryAccuracy(), metrics.AUC(curve='ROC', multi_label=True)])\n",
    "\n",
    "history = model.fit(x_train, y_train, validation_split=0.12, epochs=100, batch_size=32, callbacks=callback)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "d053893f",
   "metadata": {},
   "outputs": [],
   "source": [
    "# \"\"\"##### Save Model\"\"\"\n",
    "\n",
    "save_path = 'save_path/'\n",
    "model.save(save_path + \"First_Paper.h5\")\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "0b46abd3",
   "metadata": {},
   "outputs": [],
   "source": [
    "\"\"\"Evaluate the model\"\"\"\n",
    "\n",
    "from sklearn.metrics import precision_recall_curve, f1_score, roc_auc_score, accuracy_score, auc\n",
    "\n",
    "\n",
    "def sklearn_metrics(y_true, y_pred):\n",
    "    y_bin = np.copy(y_pred)\n",
    "    y_bin[y_bin >= 0.5] = 1\n",
    "    y_bin[y_bin < 0.5]  = 0\n",
    "\n",
    "    # Compute area under precision-Recall curve\n",
    "    auc_sum = 0\n",
    "    for i in range(no_of_classes):\n",
    "      precision, recall, thresholds = precision_recall_curve(y_true[:, i], y_pred[:,i])\n",
    "      auc_sum += auc(recall, precision)\n",
    "\n",
    "    print(\"Accuracy        : {:.2f}\".format(accuracy_score(y_true.flatten(), y_bin.flatten())* 100))\n",
    "    print(\"Macro AUC score : {:.2f}\".format(roc_auc_score(y_true, y_pred, average='macro') * 100))\n",
    "    print('AUPRC           : {:.2f}'.format((auc_sum / no_of_classes) * 100))\n",
    "    print(\"Micro F1 score  : {:.2f}\".format(f1_score(y_true, y_bin, average='micro') * 100))\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "b8e1b2cf",
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import Tuple\n",
    "import numpy as np\n",
    "import os\n",
    "\n",
    "import numpy as np\n",
    "import warnings\n",
    "from sklearn.metrics import roc_auc_score, accuracy_score\n",
    "\n",
    "\n",
    "def Metrics(y_true: np.ndarray, y_scores: np.ndarray) -> Tuple[float, float]:\n",
    "    \"\"\"Metrics for class-wise accuracy and mean accuracy.\n",
    "\n",
    "    Parameters\n",
    "    ----------\n",
    "    y_true : np.ndarray\n",
    "        Ground truth labels.\n",
    "    y_scores : np.ndarray\n",
    "        Predicted labels.\n",
    "\n",
    "    Returns\n",
    "    -------\n",
    "    tuple[np.ndarray]\n",
    "        Tuple of arrays containing class-wise accuracy and mean accuracy.\n",
    "\n",
    "    \"\"\"\n",
    "\n",
    "    y_pred = y_scores >= 0.5\n",
    "    acc = np.zeros(y_pred.shape[-1])\n",
    "\n",
    "    for i in range(y_pred.shape[-1]):\n",
    "        acc[i] = accuracy_score(y_true[:, i], y_pred[:, i])\n",
    "\n",
    "    return acc.tolist(), np.mean(acc)\n",
    "\n",
    "\n",
    "def AUC(y_true: np.ndarray, y_pred: np.ndarray, verbose: bool = False) -> float:\n",
    "    \"\"\"Computes the macro-averaged AUC score.\n",
    "\n",
    "    Parameters\n",
    "    ----------\n",
    "    y_true : np.ndarray\n",
    "        Ground truth labels.\n",
    "    y_scores : np.ndarray\n",
    "        Predicted probabilities.\n",
    "\n",
    "    Returns\n",
    "    -------\n",
    "    float\n",
    "        macro-average AUC score.\n",
    "\n",
    "    \"\"\"\n",
    "\n",
    "    aucs = []\n",
    "    assert (\n",
    "        len(y_true.shape) == 2 and len(y_pred.shape) == 2\n",
    "    ), \"Predictions and labels must be 2D.\"\n",
    "    for col in range(y_true.shape[1]):\n",
    "        try:\n",
    "            aucs.append(roc_auc_score(y_true[:, col], y_pred[:, col]))\n",
    "        except ValueError as e:\n",
    "            if verbose:\n",
    "                print(\n",
    "                    f\"Value error encountered for label {col}, likely due to using mixup or \"\n",
    "                    f\"lack of full label presence. Setting AUC to accuracy. \"\n",
    "                    f\"Original error was: {str(e)}.\"\n",
    "                )\n",
    "            aucs.append((y_pred == y_true).sum() / len(y_pred))\n",
    "    return aucs\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "9cb44cf1",
   "metadata": {},
   "outputs": [],
   "source": [
    "y_pred_train = model.predict(x_train)\n",
    "y_pred_test  = model.predict(x_test)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "31513190",
   "metadata": {},
   "outputs": [],
   "source": [
    "print(\"Train\")\n",
    "sklearn_metrics(y_train, y_pred_train)\n",
    "print(\"\\nTest\")\n",
    "sklearn_metrics(y_test, y_pred_test)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "0a7309d7",
   "metadata": {},
   "outputs": [],
   "source": [
    "acc, mean_acc = Metrics(y_test, y_pred_test)\n",
    "class_auc = AUC(y_test, y_pred_test)\n",
    "\n",
    "print(f\"class wise accuracy: {acc}\")\n",
    "\n",
    "print(f\"class wise AUC : {class_auc}\")"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.9.18"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
